/**
  * fluid - *** PLUGIN NAME ***
  * Copyright *** COPYRIGHT ***
  * 
  * Licensed under the terms of the *** LICENSE NAME *** license. 
  * 
  *     fluid Project: http://fluidjs.codeplex.com/
  *        fluid Blog: http://fluidjs.vikasburman.com
  *
  *    Repository: *** PLUGIN REPOSITORY *** 
  *  Dependencies: 
  * 	- fluid core
  *     - *** ANY OTHER DEPENDENCIES WITH DETAILS ***
  *
  */
(function($f) {	$f.extend.custom("*** UNIQUE PLUGIN NAME ***", "", "*** GUID ***", function(self) {

	"use strict";
	
	// NOTES: 
	//	1. This plugin template defines majority of structures that can be defined in
	//     a fluid plugin. 
	//
	//  2. ALL OF THESE ARE OPTIONAL. You should keep only relevant structures that
	//     you are planning to use, and should remove anything which is not used.
	//
	//  3. Refer to http://fluidjs.codeplex.com/documentation to know about all possibilities 
	//     and other details.


	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	// vvvvvvvvvvvvvvvvvv PRIVATE VARS, FUNCTIONS AND CLASSES vvvvvvvvvvvvvvvvv
	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv	
	
	// all private variables, functions and classes 
	// can be defined here
	
	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	// vvvvvvvvvvvvvvvvvvvvvvvvvv PLUGIN DEFINITION  vvvvvvvvvvvvvvvvvvvvvvvvvv
	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	
	// plugin info
	this.info = {
		title: "",
		version: "", // major.minor.build
		author: "",
		copyright: "",			
		description: "",
		web: "",
		license: {
			text: "",
			url: ""
		}
	};
	
	// pre-initialization handler
	// called just after plugin instance is created and no features or includes are processed
	// returns (boolean): 
	//	true: if success 
	//	false: if failed
	this.onPreInit = function() { 
		// any initialization goes here, if any
		var isSuccess = true;
		
		// return
		return isSuccess;
	};
	
	// initialization handler
	// called when all includes are processed and features etc. are added
	// returns (boolean): 
	//	true: if success 
	//	false: if failed
	this.onInit = function() { 
		// any initialization goes here, if any
		var isSuccess = true;
		
		// return
		return isSuccess;
	};

	// load handler
	// returns: (void)
	this.onLoad = function() { 
	};
	
	// ready handler
	// returns: (void)
	this.onReady = function() { 
	};
	
	// unload handler
	// returns: (void)
	this.onUnload = function() { 
	};
	
	// reset handler
	// returns: (void)
	this.onReset = function() {
	};
	
	// restart handler
	// returns: (void)
	this.onRestart = function() {
	};
	
	// configure given plugin 
	// this is called for each plugin if canConfigurePlugins is set to true
	// params:
	//	plugin (object): plugin object to configure
	//	isPerformOnLoadProcessAlso (boolean): if perform those functions also that are otherwise done 
	//										  at onLoad of this plugin otherwise should also be done now with
	//                                        this plugin, because this is being loaded after all
	//                                        batch processing is done at load time
	//	isReconfigureOnNewFeatureAdd (boolean): if reconfiguration of plugin is required because
	// 										    a new feature is added to plugin which may have added
	//											some members those required reconfiguration
	// returns (void):	
	this.configure = function(plugin, isPerformOnLoadProcessAlso, isReconfigureOnNewFeatureAdd) {
	};
	
	// plugin variables
	// value of these variables is NOT maintained across page refresh
	this.vars = { 
	};
	
	// plugin configuration
	this.config = {
		// name of the resource JSON file (without path)
		// same name file MUST be present having identical structure in each locale specific folder 
		// under RESOURCE-FOLDER content of this file is loaded in "resources" object of the 
		// plugin, if this is empty, no resources are loaded
		resourceJSON: "",
		
		// if global weavings as defined in app plugin are to be applied over this plugin
		isApplyGlobalWeavings: false
	};
	
	// plugin settings (contents here-in must be JSON serializable)
	// if items are defined here, these will be maintained under "settings" node in  
	// application configuration file
	// items must be defined here with their initial value - it will be replaced with an object
	// at runtime which can be accessed as:
	// this.settings.<name>.get() to get it, this.settings.<name>.set(<value>) to set it
	this.settings = { 
	};

	// plugin entries in session (contents here-in must be JSON serializable)
	// if items are defined here, these will be maintained in session
	// items must be defined here with their initial value - it will be replaced with an object
	// at runtime which can be accessed as:
	// this.session.<name>.get() to get it, this.session.<name>.set(<value>) to set it
	this.session = { 
	};
	
	// plugin state (contents here-in must be JSON serializable)
	// if items are defined here, these will be preserved across page refresh (by 
	// serializing/deserializing transparently)
	this.state = { 
	};
	
	// called just before the state is being picked for
	// persiatance 
	this.beforeSaveState = function() {
	};
	
	// called when state of the plugin is reloaded 
	// from persiatance store
	this.afterLoadState = function() {
	};
	
	// plugin entries in cache (contents here-in must be JSON serializable)
	// if items are defined here, these will be maintained in cache
	// items must be defined here with their initial value - it will be replaced with an object
	// at runtime which can be accessed as:
	// this.cache.<name>.get() to get it, this.cache.<name>.set(<value>) to set it
	this.cache = { 
	};
	
	// external files which are to be loaded during initialization process
	// value of each item here should be 
	// { name: "", file: "", cond: "an optional function that returns true/false for conditional include" }
	// files are loaded in specified order one after another
	// files of following types can be included:
	// JavaScript (*.js), Stylesheets (*.css) and Templates (*.html) and any other type of files which
	// are defined in "dynamicHtmlEndPoints" configuration setting
	this.include = [
	];

	// plugin events, subscriptions and handlers
	this.events = { 
		// a namespace for all the events in this plugin
		// when events are registered globally, this will be prefixed with
		// all specified events of this plugin
		// E.g., if the namespace is: AppName.Pages.Order
		// and event name is "Created"
		// the publicly registered event that will be AppName.Pages.Order.Created		
		namespace: "",

		// define one item for each event - at runtime this will be replaced by an event object
		// each item here is defined as:
		// <FriendlyEventName>: "ScopeQualifiedEventName"
		// a scope qualified event name must be unique across application 
		// each event object has three methods
		//	publish(args)
		// 	subscribe(handler)
		//	unsubscribe(handler)
		// ... event definitions goes here ...
		
		// event subscriptions
		// define one item for each subscription - at runtime this will wire event subscriptions
		// and will be replaced by an event subscriptions object
		// each item here should be defined such:
		// <eventHandlerFunctionName>: ["FullyQualifiedEventNameToWhichToBindTo", "..."]
		// These eventHandlerFunctionName must exists under "handlers" section
		subscriptions: { 
		},
	
		// event handlers
		// each item define one event handler as:
		// <eventHandlerFunctionName>: function(e) { }
		// e is an object having following properties:
		//	name: fully qualified name of the event (incuding namespace)
		//	sender: sender object of the event
		//	args: what args were passed when event was raised
		//	cancel: a method to cancel further execution of the event propogation code
		handlers: { 
		}
	},
	
	// plugin aspects
	// define one item for each aspect - at runtime this will be replaced by an aspect object
	// each aspect object should container following
	// 	before (function)
	//	after (function)
	//  args (optional object literal) - will be passed to before and after functions
	// e.g.,
	//	<name>: {before: function(context, args) { }, after: function(context, args) {}, args: {}}
	//  NOTE: at least one between "before" or "after" must be provided. Both can also be provided
	this.aspects = { 
	};
	
	// plugin weavings
	// this works in specified order
	// define one item for each weaving - at runtime weavings will be done based on this
	// each item here should be defined such:
	//	{plugin: "" , aspect: "published aspectName", functions: ["func1", "func2"]}
	// NOTE: function names can have * wildcard in one of the following ways: funcName* OR *funcName OR func*Name
	this.weavings = [
	];
	
	// plugin database access
	// define one item for each database - at runtime this will be replaced by a database object
	// value of each named item here should be name of the required database.
	// database definition must be defined by inclusion of relevant JS files in "include"
	this.db = { 
	};
	
	// plugin shortcut keys
	// value of each named item here should define a shortcut key and corrosponding handler
	// key codes can be referred at: http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
	// defName: {enable: true|false|function, modifier: "shift|alt|ctrl", code: code, handler: <handler function>}
	this.hotkeys = { 
	};
	
	// plugin workflows
	// define one item for each workflow - at runtime a workflow handle object would replace this definition
	// a workflow can be started with .start() and can be aborted using stop() function
	// a workflow executes in async mode only - so it returns immediately from start
	// each named (array) item here should be defined such:
	// <workflowName>: 
	// [
	// {begin: function(context) { }},
	// {...},
	// {<name>: function(context) { }},
	// {...},
	// {for: "<context.decisionVariable>", branch: [
	// 		{on: "<value1>", <name>: function(context) { }},
	// 		{on: "<value2>", <name>: function(context) { }},
	// 		{on: "<value3>", <name>: function(context) { }},
	// 		{else: function(context) { }}			
	// ]},
	// {...},
	// {<name>: function(context) { }},
	// {...},
	// {fork: [
	//		{<name>: function(context, callback) { }}, 
	//		{<name>: function(context, callback) { }}, 
	//		{...}
	// ]},
	// {...},
	// {<name>: function(context) { }},
	// {...},
	// {<name>: function(context) { }},
	// {...},
	// {after: "name1, name2, ...", join: function(context) { }},
	// {...},
	// {<name>: function(context) { }},
	// {...},
	// {<name>: function(context) { }},
	// {...},
	// {pause: function(context) { }),
	// {resume: function(context) { }),
	// {abort: function(context) { }},
	// {catch: function(stepName, ex, context) { return true | false }},
	// {finally: function(context) { }},
	// {end: function(context) { }}
	// ]
	// NOTES:
	//	- there should only one begin, abort, end, catch and finally element (first occurance of it will be used, rest
	//    will be ignored)
	//	- step represents a sync call, if an async operation is called internally it is on its own
	//	- each function defined here except functions inside "fork" should take only one parameter "context"
	//	- catch takes stepName (where exception occured), ex (real exception), and context
	//	- no function is expected to return any value - any result value that needs to be
	//	  shared, should be stored in context
	//	- callback function passed in begin is optional but if passed should accept context object
	//	- branch defines a property name in context object in "for" whose value is read and based on matching
	//    "on" value, branch to execute is picked. If no value matches, else function is picked
	//    branch
	//	- branch can nest any other step, fork or branch nodes and there is no limit of depth for these
	//	- fork takes an array functions which must be making async calls inside it - it also takes a callback
	//    parameter which is an internal function which must be called with name of the forked function and
	//	  any error details. Callback signatures are: callback(name, isError, ex)
	//	- fork cannot nest anything else other then the defined function
	//	- join waits for given named forked steps to complete before calling the join function. In case no
	//	  "after" names are given, it waits for all running forked steps
	//	- end waits for all running forked steps and calls function only when everything is done
	//  - if an exception occured during executing any function or an exception was reported by a forked
	//    function via callback, catch is called with details - based on the return value of catch further
	//    execution is called or stopped (true means error handled - continue, false means stop
	//	- abort is called only when workflow was aborted from outside 
	//	- finally is called everytime catch was called and after abort was called and before end was called
	//	- all named defined here MUST be unique
	//	- pause function is called when for some reasons workflow is being paused either by user manually or
	//    because of page refresh
	//	- resume function is called when a paused workflow is resumed
	this.workflows = { 
	};
	
	// plugin scheduled jobs
	// define one item for each scheduled job - at runtime scheduled jobs will be created accordingly
	// each item here should be defined such:
	//	<jobName>: {method: "methodNameOfPlugin", interval: scheduleRunIntervalInMilliSeconds, isAutoStart: true|false}
	this.jobs = { 
	};
	
	// plugin service facade
	// define one item for each service - at runtime this will be replaced by a service object
	// that can be called as: <plugin>.services.<name>.{call|<actionName>}(data, onSuccessCallback, onErrorCallback);
	// each service item should define $.ajax() call parameters except "data", "success" and "error" values
	// e.g.,
	//	<name>: {all/any values that $.ajax requires except "data", "success" and "error"}		
	this.services = { 
	};
	
	// called before an ajax call to server is made via framework by this plugin
	// params:
	//	serviceName (string): name of the service for conditional processings, if any
	//	params (object literal): original params object using which call is being made
	// returns (object literal): original or modified params object - call will be made using this object
	this.onServerRequest = function(serviceName, params) {
		// return as is by default
		return params;
	};
	
	// called on receiving a success from a server response to an ajax call
	// params:
	//	serviceName (string): name of the service for conditional processings, if any
	//	params (object literal): original (or modified) params object for which this response success is received
	//	successResponse (object literal): object having ajax success call parameters
	// returns (object): possibly modified server response object
	this.onServerResponseSuccess = function(serviceName, params, successResponse) { 
		// return as is by default
		return successResponse;
	};
	
	// called on receiving an error from a server response to an ajax call
	// params:
	//	serviceName (string): name of the service for conditional processings, if any
	//	params (object literal): original (or modified) params object for which this response error is received
	//	errorResponse (object literal): object having ajax error call parameters
	// returns (object): possibly modified server response object
	this.onServerResponseError = function(serviceName, params, errorResponse) { 
		// return as is by default
		return errorResponse;
	};

	// called when a feature is going to be merged into this plugin
	// this can sniff the feature and see if it is allowed to be merged
	// this is called before feature is instantiated and any merge conflicts are checked for
	// NOTE: no change should be done on provided definition
	// params:
	//	featureItem (object): feature item definition  
	//                        {name: name, target: target, id: featureItemId, extender: extender};
	// returns (boolean): true, if allowed, false otherwise
	this.onBeforeFeatureAdd(feature) {
		// return
		return true;
	};

	// called when a feature was merged into this plugin
	// this can do anything else that is required after a certain feature was added
	// params:
	//	featureItem (object): feature item definition  
	//                        {name: name, target: target, id: featureItemId, extender: extender};
	// returns (void): 
	this.onAfterFeatureAdd(feature) {
	};
	
	// (p as in) "private" functions of this plugin
	// anything that is not for public use
	// backward compatibility will not be expected by other plugins
	this.p = { 
	};
}); }(fluid));
